#include <raytrace.h>
#include <camera.h>
#include <debug.h>
#include <visual.h>
#include <scene.h>
#include <sphere.h>
#include <light.h>

#define TODO( str ) printf("TODO : %s\n", str );

int
main( int argc, char *argv[] )
{
  surface_t *surface;

  debug_level = DEBUG_DBG;

  int d = 250;

#ifndef _DEBUG

  visual_init( d, d );

#endif

  surface = surface_new( d, d );

  coord_t pos0 = { 0, 0 };

  camera_t camera = {
    .center = { .data = { 0 , 0, 500 } },
    .normal = { .data = { 0 , 0, -1 } },
    .distance = 100,
    .rotx = 0.0,
    .roty = (3.14/2),
    .surface = surface
  };

  scene_t *scene = scene_new();

  sphere_t *sphere;
  color_t color;

  // sphere 1
  sphere = sphere_new();
  assert( scene != NULL );

  SPHERE_X( sphere ) = 270;
  SPHERE_Y( sphere ) = 0;
  SPHERE_Z( sphere ) = 270;

  COLOR_FROM_ARGB( color, COLOR_RED );
  object_init4( OBJECT( sphere ), color, 0.6, 0 );
  OBJECT( sphere )->kd = 0.7; // difuse
  OBJECT( sphere )->ks = 0.2; // specular
  OBJECT( sphere )->nphong = 50; // phongs
  sphere->radius = 70;
  scene_add_object( scene, OBJECT( sphere ) );

  // sphere 2
  sphere = sphere_new();
  assert( scene != NULL );

  SPHERE_X( sphere ) = 0;
  SPHERE_Y( sphere ) = 0;
  SPHERE_Z( sphere ) = 0;

  COLOR_FROM_ARGB( color, COLOR_BLUE );
  object_init4( OBJECT( sphere ), color, 0.5, 0 );
  OBJECT( sphere )->kd = 0.7; // difuse
  OBJECT( sphere )->ks = 0.2; // specular
  OBJECT( sphere )->nphong = 7; // phongs
  sphere->radius = 200;
  scene_add_object( scene, OBJECT( sphere ) );


  // sphere 3
  sphere = sphere_new();
  assert( scene != NULL );

  SPHERE_X( sphere ) = 300;
  SPHERE_Y( sphere ) = 0;
  SPHERE_Z( sphere ) = 0;

  COLOR_FROM_ARGB( color, COLOR_GREEN );
  object_init4( OBJECT( sphere ), color, 0.5, 0 );
  OBJECT( sphere )->kd = 0.7; // difuse
  OBJECT( sphere )->ks = 0.2; // specular
  OBJECT( sphere )->nphong = 2; // phongs
  sphere->radius = 100;
  scene_add_object( scene, OBJECT( sphere ) );

  light_t *light;

  light = light_new();
  assert( light != NULL );

  LIGHT_X( light ) = 400;
  LIGHT_Y( light ) = 0;
  LIGHT_Z( light ) = 400;

  linkedlist_t *ilumination = list_new();

  struct object_node *node;

  node = list_add( ilumination, struct object_node );
  node->object = ( object_t * )light;


  light = light_new();
  assert( light != NULL );

  LIGHT_X( light ) = 0;
  LIGHT_Y( light ) = 0;
  LIGHT_Z( light ) = -400;

  node = list_add( ilumination, struct object_node );
  node->object = ( object_t * )light;

  light_t *l;
  for_each_list_element( ilumination, node ){
    l = (light_t*)node->object;
    char *str;
    str = light_str( l );
    printf("%s\n", str );
    free( str );
  }

  //scene_raytrace( scene, camera, light );
  scene_raytrace( scene, camera, ilumination );

#ifndef _DEBUG

  visual_display( surface, pos0 );
  visual_update();
  visual_waitkey();
  //return 1;
#else
  return 1;
#endif

  int i,j;

  vector3_t ref;
  VECTOR3_X( ref ) = 400;
  VECTOR3_Y( ref ) = 0;
  VECTOR3_Z( ref ) = 0;

  //while(1){
  for( j = 0 ; j < 4 ; j++ ){
    for( i = 1 ; i < 360 ; i+= 10 ){

      light = light_new();
      assert( light != NULL );
      LIGHT_X( light ) = 400;
      LIGHT_Y( light ) = 0;
      LIGHT_Z( light ) = 400;

      switch( j ){
      case 0:{
	camera.roty = ((double) 2*3.14 / (double) 360) * (double) i;
	break;
      }
      case 1:{
	camera.rotx = ((double) 2*3.14 / (double) 360) * (double) i;
	break;
      }
      case 2:{
	camera.roty = ((double) 2*3.14 / (double) 360) * (double) i;
	camera.rotx = ((double) 2*3.14 / (double) 360) * (double) i;
	break;
      }
      default :{
	camera.roty = ((double) 2*3.14 / (double) 360) * (double) i;
	camera.rotx = ((double) 2*3.14 / (double) 360) * (double) i;
	break;
      }
      }

      char *s = light_str( light );
      printf("%s\n",s);
      free( s );

      //scene_raycast( scene, camera );
      //scene_raytrace( scene, camera, light );
      scene_raytrace( scene, camera, ilumination );

      visual_display( surface, pos0 );
      visual_update();
      surface_clear( surface );

    }
  }

  TODO( "don't forget to free sphere objets !!" );

  //sphere_free( sphere );
  //scene_free_objects( scene );
  visual_quit();

  return 0;
}
